package com.vcredit.creditcat.bean;

import com.google.common.hash.Hashing;
import com.vcredit.creditcat.interceptor.CreditCatExceptionConverter;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import org.apache.log4j.Logger;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.util.ClassUtils;

/**
 * @description: ${todo} (解决Spring默认的SimpleKeyGenerator是不会将函数名组合进key中的，多参数、原子类型数组、方法名识别 等问题) from:http://blog.csdn.net/syani/article/details/52239967
 * Project Name:credit_cat File Name:CacheKeyGenerator.java
 * Copyright (c) 2017/9/29 @author: 张新功 Inc.All Rights Reserved.
 */
class CacheKeyGenerator implements KeyGenerator {
  Logger log = Logger.getLogger(CacheKeyGenerator.class);
  // custom cache key
  public static final int NO_PARAM_KEY = 0;
  public static final int NULL_PARAM_KEY = 53;

  @Override
  public Object generate(Object target, Method method, Object... params) {

    StringBuilder key = new StringBuilder();
    key.append(target.getClass().getSimpleName()).append(".").append(method.getName()).append(":");
    if (params.length == 0) {
      return key.append(NO_PARAM_KEY).toString();
    }
    for (Object param : params) {
      if (param == null) {
        log.warn(MessageFormat.format("input null param for Spring cache, use default key={0}", NULL_PARAM_KEY));
        key.append(NULL_PARAM_KEY);
      } else if (ClassUtils.isPrimitiveArray(param.getClass())) {
        int length = Array.getLength(param);
        for (int i = 0; i < length; i++) {
          key.append(Array.get(param, i));
          key.append(',');
        }
      } else if (ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String) {
        key.append(param);
      } else {
        log.warn("Using an object as a cache key may lead to unexpected results. " +
            "Either use @Cacheable(key=..) or implement CacheKey. Method is " + target.getClass() + "#" + method.getName());
        key.append(param.hashCode());
      }
      key.append('-');
    }

    String finalKey = key.toString();
    long cacheKeyHash = Hashing.murmur3_128().hashString(finalKey, Charset.defaultCharset()).asLong();
    log.debug(MessageFormat.format("using cache key={0} hashCode={1}", finalKey, cacheKeyHash));
    //log.info(key.toString());
    return key.toString();
  }
}
